using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using ZoneFiveSoftware.Common.Data.Fitness;

namespace FilteredStatistics.Common.Controller
{
    public class FilterCriteriaController
    {
        private FilterCriteriaController()
        {
        }

        private void OnProviderFilterCriteriasChanged(object sender, PropertyChangedEventArgs e)
        {
            m_AvailableCriterias = null;
            TriggerAvailableCriteriasChanged();
        }

        public void ReloadAvailableCriterias(ILogbook logbook)
        {
            m_AvailableCriterias = null;
            RefreshCriteriasList(logbook);
            TriggerAvailableCriteriasChanged();
        }

        public void RegisterFilterCriteriaProvider(object provider)
        {
            IFilterCriteriaProvider newProvider = null;

            if (provider is IFilterCriteriaProvider)
            {
                newProvider = provider as IFilterCriteriaProvider;
            }
            else
            {
                newProvider = CreateProviderProxy(provider);

                Debug.Assert(newProvider != null);
            }

            newProvider.FilterCriteriasChanged += new PropertyChangedEventHandler(OnProviderFilterCriteriasChanged);
            Providers.Add(newProvider);

            m_AvailableCriterias = null;
            TriggerAvailableCriteriasChanged();
        }

        private void RefreshCriteriasList(ILogbook logbook)
        {
            if (m_AvailableCriterias == null)
            {
                m_AvailableCriterias = new Dictionary<Guid, IFilterCriteria>();

                foreach (IFilterCriteriaProvider provider in Providers)
                {
                    foreach (object criteria in provider.GetFilterCriterias(logbook))
                    {
                        IFilterCriteria newCriteria;

                        if (criteria is IFilterCriteria)
                        {
                            newCriteria = criteria as IFilterCriteria;
                        }
                        else
                        {
                            newCriteria = FilterCriteriaFacade.CreateProxyFilterCriteria(criteria);

                            Debug.Assert(newCriteria != null);
                        }

                        if (!m_AvailableCriterias.ContainsKey(newCriteria.ReferenceId))
                        {
                            m_AvailableCriterias.Add(newCriteria.ReferenceId, newCriteria);
                        }
                    }
                }
            }
        }

        private IFilterCriteriaProvider CreateProviderProxy(object provider)
        {
            IFilterCriteriaProvider result = null;

            try
            {
                result = new ProxyFilterCriteriaProvider(provider);
            }
            catch(Exception e)
            {
                Debug.Assert(false, e.Message);
            }

            return result;
        }

        public IFilterCriteria GetCriteria(Guid referenceId)
        {
            if (AvailableCriteriasDictionnary.ContainsKey(referenceId))
            {
                return AvailableCriteriasDictionnary[referenceId];
            }

            return null;
        }

        private void TriggerAvailableCriteriasChanged()
        {
            if (AvailableCriteriasChanged != null)
            {
                AvailableCriteriasChanged(this, new PropertyChangedEventArgs("AvailableCriterias"));
            }
        }

        public static FilterCriteriaController Instance
        {
            get
            {
                if (m_Instance == null)
                {
                    m_Instance = new FilterCriteriaController();
                }

                return m_Instance;
            }
        }

        private Dictionary<Guid, IFilterCriteria> AvailableCriteriasDictionnary
        {
            get
            {
                if (PluginMain.GetApplication() != null)
                {
                    RefreshCriteriasList(PluginMain.GetApplication().Logbook);
                }

                return m_AvailableCriterias;
            }
        }

        private List<IFilterCriteriaProvider> Providers
        {
            get { return m_Providers; }
        }

        public IFilterCriteria[] AvailableCriterias
        {
            get
            {
                if (AvailableCriteriasDictionnary != null)
                {
                    IFilterCriteria[] result = new IFilterCriteria[AvailableCriteriasDictionnary.Values.Count];

                    AvailableCriteriasDictionnary.Values.CopyTo(result, 0);

                    return result;
                }

                return null;
            }
        }
        
        public IActivity Activity
        {
            set
            {
                foreach (IFilterCriteria criteria in AvailableCriterias)
                {
                    criteria.Activity = value;
                }
            }
        }

        public event PropertyChangedEventHandler AvailableCriteriasChanged;

        private static FilterCriteriaController m_Instance = null;
        private List<IFilterCriteriaProvider> m_Providers = new List<IFilterCriteriaProvider>();
        private Dictionary<Guid, IFilterCriteria> m_AvailableCriterias;
    }
}
